diag(ffmpeg): name the libavcodec that answered, not "this build" - #404
Merged
Conversation
AE#396 was reported as an audio-bridge defect and was a second FFmpeg. The host linked a static libavcodec 61 with -force_load, so its symbols became ordinary definitions in the executable and beat the engine's dylibs; the engine ran against headers it was never compiled against. Its only trace was "flac bridge encoder absent from this FFmpeg build", a true sentence about a build that was not ours, and it reads as a claim about ours. Five fixtures and two devices before anyone looked at the link. The engine could not notice. avcodec_version and avcodec_configuration appeared zero times in Sources/. FFmpegRuntimeCheck compares the compile-time major of all four linked libraries against what the loaded binaries report, and emits the verdict once from init: the four versions when they match, and otherwise an ERROR naming the mismatched libraries, the two shapes that cause it (a force-loaded static archive, a dependency exporting the same symbols such as libVLC), the nm/otool probes that show which binary wins, and the configure line of the libavcodec that answered. The encoder-absence message carries that identity too, so a statement about "this FFmpeg build" always says which one. Docs: a linking contract in docs/api.md, and the README's static-linking and diagnostics sections, because being dynamically embedded is not the same as being reached. Reported and diagnosed by @kskchaitanya1993, who also supplied the host-side reproduction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5UztmCZtNYPQpzdmSdmWG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes nothing; AE#396 turned out to be host-side, and the reporter fixed it themselves. What is left is the part that was ours: the engine had no way to notice it was running against a different FFmpeg, and the one line it did emit described someone else’s build as if it were ours.
What AE#396 was
The reporting app linked a second FFmpeg: an older internal module shipped libavcodec 61 as a static archive,
-force_loaded, so itsavcodec_*became ordinary definitions in the executable and beat the engine’s dylibs for every other object in the same link. AetherEngine expects 62 and executed against 61. Every bridged source on that build emitted nothing, on five fixtures across three codecs and two containers, and on their own tvOS app (same engine, same file, no second FFmpeg) the same file played.The trace the engine left was:
True, and about a build that was not ours.
avcodec_versionandavcodec_configurationappeared zero times inSources/.What this adds
FFmpegRuntimeCheckcompares the compile-time major of all four linked libraries against what the loaded binaries answer, and emits the verdict once fromAetherEngine.init:On a mismatch that becomes an
ERROR:naming the mismatched libraries with both majors, the two shapes that cause it (a force-loaded static archive; a dependency exporting the same symbols, libVLC among them), thenm -m/otool -Lprobes that show which binary wins, and the configure line of the libavcodec that actually answered. libavutil matters more than libavcodec here: a major shift there moves struct layouts, which is a crash rather than a silence.The encoder-absence message now carries that identity, so a claim about "this FFmpeg build" always says which one.
Docs
A linking contract in
docs/api.md, and the README’s static-linking and diagnostics sections, because being dynamically embedded is not the same as being reached. libVLC beside AetherEngine is an ordinary shape for the fallback ladder this API invites, and CocoaPods sorts a pod ahead of a vendored framework by default.Not done
Namespacing the vendored FFmpeg symbols, the reporter’s second suggestion. It would need a post-build symbol rewrite across eight slices plus rewritten headers, and it breaks every consumer that uses the FFmpeg headers directly. The cause is link order in the host, which only the host can set; what was missing was a witness, not a rename.
Tests
11 new, TDD, and the sharp one is
testLoadedLibrariesMatchTheHeadersThisBuildCompiledAgainst: it fails in exactly the situation AE#396 was. Mutation-checked (compiled major +1 fails it, and names the reason). Full suite 1955 tests green.Reported and diagnosed by @kskchaitanya1993.
🤖 Generated with Claude Code
https://claude.ai/code/session_01E5UztmCZtNYPQpzdmSdmWG